package org.tgcloud.group.core.fileUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import org.tgcloud.group.core.DateUtil;
import org.tgcloud.group.core.GlobalStatic;
import org.tgcloud.group.core.SevenAuthUtil;
import sun.misc.BASE64Decoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by cloudLiu on 2015/8/6.
 */
public class UpLoadFile {

    private static Logger logger = LoggerFactory.getLogger(FileUtil.class);

    /**
     * 删除文件
     * @param filePath 文件绝对路径
     */
    public static void delFile(String filePath) {
        File myDelFile = new File(filePath);
        if (myDelFile.exists()) {
            myDelFile.delete();
        }
    }

    public static String uploadNetFile(String urlString){
        URL url = null;
        Map<String,String> paths = checkFilePath(0);
        try {
            url = new URL(urlString);
            DataInputStream dataInputStream = new DataInputStream(url.openStream());
            String storeName = rename(".jpg");
            File targetFile = new File(paths.get("path"), storeName);
            FileOutputStream fileOutputStream = new FileOutputStream(targetFile);
            ByteArrayOutputStream output = new ByteArrayOutputStream();

            byte[] buffer = new byte[1024];
            int length;

            while ((length = dataInputStream.read(buffer)) > 0) {
                output.write(buffer, 0, length);
            }
            byte[] context=output.toByteArray();
            fileOutputStream.write(output.toByteArray());
            dataInputStream.close();
            fileOutputStream.close();
            return  paths.get("modelpath")+storeName;

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 获取文件大小
     * @param file
     * @return
     * @throws IOException
     */
    public static long getFileSize(File file) throws IOException {
        long s = 0;
        if (file.exists()) {
            return file.length();
        }
        return s;
    }

    /**
     * 转换文件大小
     * @param files
     * @return
     */
    public static String formateFileSize(long files) {
        DecimalFormat df = new DecimalFormat("#.00");
        String fileSizeString = "";
        if (files < 1024) {
            fileSizeString = df.format((double) files) + "B";
        } else if (files < 1048576) {
            fileSizeString = df.format((double) files / 1024) + "K";
        } else if (files < 1073741824) {
            fileSizeString = df.format((double) files / 1048576) + "M";
        } else {
            fileSizeString = df.format((double) files / 1073741824) + "G";
        }
        return fileSizeString;
    }

    /**
     * 复制文件
     * @param src
     * @param dest
     * @throws IOException
     */
    public static void copy(File src, File dest) throws IOException {
        if (!dest.exists())
            dest.createNewFile();
        transfer(new FileInputStream(src), new FileOutputStream(dest));
    }

    /**
     * 复制文件
     * @param src
     * @param dest
     * @throws IOException
     */
    public static void transfer(FileInputStream src, FileOutputStream dest) throws IOException {
        FileChannel source = null;
        FileChannel target = null;
        try {
            source = src.getChannel();
            target = dest.getChannel();
            long position = 0, size = source.size();
            while ((position += source.transferTo(position, size - position, target)) < size)
                ;
        } finally {
            if (src != null) {
                try {
                    source.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (dest != null) {
                try {
                    target.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 复制输入流到指定的输出流
     * @param _in
     * @param _out
     */
    public static void copy(InputStream _in, OutputStream _out) {
        InputStream in = null;
        OutputStream out = null;
        try {
            in = new BufferedInputStream(_in);
            out = new BufferedOutputStream(_out);
            byte[] b = new byte[1024];
            int len = 0;
            while ((len = in.read(b, 0, b.length)) != -1) {
                out.write(b, 0, len);
            }
            out.flush();
        } catch (Exception e) {
        } finally {
            close(in, out);
        }
    }

    /**
     * add by panmg copy一个文件夹下面的文件到另一个文件夹
     * @param source 必须是文件夹
     * @param target 必须是文件夹
     * @throws IOException
     */
    public static void copyFolder(String source, String target) throws IOException {
        new File(target).mkdirs(); // 目标文件夹
        File fsource = new File(source);
        String[] fNames = fsource.list();
        for (String name : fNames) {
            File temp = new File(source + "/" + name);
            if (temp.isFile()) {
                FileInputStream in = null;
                FileOutputStream out = null;
                try {
                    in = new FileInputStream(temp);
                    out = new FileOutputStream(target + "/" + name);
                    byte[] b = new byte[10240];
                    int len;
                    while ((len = in.read(b)) != -1) {
                        out.write(b, 0, len);
                    }
                } finally {
                    if (out != null)
                        out.close();
                    if (in != null)
                        in.close();
                }
            } else {
                copyFolder(source + "/" + name, target + "/" + name);
            }

        }
    }


    /**
     * add by panmg 删除某个文件夹中的文件
     * @param ObjectPath
     */
    public static void deleteDirectory(String ObjectPath) {
        File file = new File(ObjectPath);
        if(!file.exists()) return;
        File[] files = file.listFiles();
        for (File f : files) {
            if (f.isFile()) {
                f.delete();
            } else {
                /* 先删除文件夹的内文件, 在删文件夹 */
                deleteDirectory(ObjectPath + "/" + f.getName());
                f.delete();
            }
        }
    }

    /**
     * 关闭资源
     * @param in
     * @param out
     */
    public static void close(InputStream in, OutputStream out) {
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                in = null;
            }
        }
        if (out != null) {
            try {
                out.close();
            } catch (IOException e) {
                in = null;
            }
        }
    }

    /**
     * add by panmg
     * @param in
     * @param out
     * @param width
     * @param height
     * @param proportion
     * @throws IOException
     */
    public static void compressPic(InputStream in, OutputStream out, int width, int height, boolean proportion) throws IOException {
        // 获得源文件
        java.awt.Image img = ImageIO.read(in);
        if(img.getWidth(null)==width && img.getHeight(null)==height)  return;
        int newWidth, newHeight;
        // 判断是否是等比缩放
        if (proportion == true) {
            // 为等比缩放计算输出的图片宽度及高度
            double rate1 = ((double) img.getWidth(null)) / (double) width + 0.1;
            double rate2 = ((double) img.getHeight(null)) / (double) height + 0.1;
            // 根据缩放比率大的进行缩放控制
            double rate = rate1 > rate2 ? rate1 : rate2;
            newWidth = (int) ((img.getWidth(null)) / rate);
            newHeight = (int) ((img.getHeight(null)) / rate);
        } else {
            newWidth = width; // 输出的图片宽度
            newHeight = height; // 输出的图片高度
        }

        BufferedImage tag = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
        /*
         * Image.SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的 优先级比速度高 生成的图片质量比较好 但速度慢
         */
        tag.getGraphics().drawImage(img.getScaledInstance(newWidth, newHeight, java.awt.Image.SCALE_SMOOTH), 0, 0, null);
        // JPEGImageEncoder可适用于其他图片类型的转换
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
        encoder.encode(tag); // 近JPEG编码
        out.close();
    }

    /**
     * add by panmg
     * @param in
     * @param out
     * @param width
     * @param height
     * @param proportion
     * @throws IOException
     */
    public static double compressPic(InputStream in, OutputStream out, int width, int height, boolean proportion, int type) throws IOException {
        // 获得源文件
        java.awt.Image img = ImageIO.read(in);
        //if(img.getWidth(null)==width && img.getHeight(null)==height)  return 1;
        int newWidth, newHeight;
        double oldWidth=img.getWidth(null);
        double oldHeight=img.getHeight(null);
        // 判断是否是等比缩放
        if (proportion == true) {
            // 为等比缩放计算输出的图片宽度及高度
            double rate1 = ((double) img.getWidth(null)) / (double) width + 0.1;
            double rate2 = ((double) img.getHeight(null)) / (double) height + 0.1;
            // 根据缩放比率大的进行缩放控制
            double rate = rate1 > rate2 ? rate1 : rate2;
            newWidth = (int) ((img.getWidth(null)) / rate);
            newHeight = (int) ((img.getHeight(null)) / rate);
        } else {
            newWidth = width; // 输出的图片宽度
            newHeight = height; // 输出的图片高度
        }

        BufferedImage tag = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
        /*
         * Image.SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的 优先级比速度高 生成的图片质量比较好 但速度慢
         */
        tag.getGraphics().drawImage(img.getScaledInstance(newWidth, newHeight, java.awt.Image.SCALE_SMOOTH), 0, 0, null);
        // JPEGImageEncoder可适用于其他图片类型的转换
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
        encoder.encode(tag); // 近JPEG编码
        out.close();
        if(type==1){
            return DateUtil.div(oldWidth, oldHeight, 2);
        }else{
            return 1;
        }
    }

    /**
     * 将上传的文件进行重命名
     * @param name
     * @return
     */
    public static String rename(String name) {

        Long now = Long.parseLong(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
        Long random = (long) (Math.random() * now);
        String fileName = now + "" + random;

        if (name.indexOf(".") != -1) {
            fileName += name.substring(name.lastIndexOf("."));
        }

        return fileName;
    }

    /**
     * 单文件上传，返回文件访问路径.
     * type: 0---普通用户头像;1-商品介绍图片上传;
     * @param myfile
     * @param type
     * @return
     */
    public static String upload(MultipartFile myfile, Integer type)
    {
        Map<String,String> paths = checkFilePath(type);
        //上传文件重命名再存储
        String storeName = rename(myfile.getOriginalFilename());
        File targetFile = new File(paths.get("path"), storeName);
        try{
            myfile.transferTo(targetFile);
            String modelpath = paths.get("modelpath") + storeName;//存入数据库文件后面拼接文件名
            return modelpath;
        }catch(Exception e){
            logger.error("文件上传失败");
            e.printStackTrace();
            return null;
        }
    }

    public static String uploadPicFromW(InputStream inputStream, Integer type){
        Map<String,String> paths = checkFilePath(type);
        String storeName = rename(".jpg");
        File targetFile = new File(paths.get("path"), storeName);
        try{
//            myfile.transferTo(targetFile);
            String modelpath = paths.get("modelpath") + storeName;//存入数据库文件后面拼接文件名
            return modelpath;
        }catch(Exception e){
            logger.error("文件上传失败");
            e.printStackTrace();
            return null;
        }
    }

    /*检查路径是否存在*/
    public static Map<String,String> checkFilePath(Integer type)
    {
        //上传文件的路径
        String path = null;
        //相对路径
        String modelpath = null;
        if (type == null)
        {
            type = 0;
        }
        if(type == 0){
            path = GlobalStatic.uploadPath + "/img/user";//
            modelpath = "/img/user/";
        }else if(type == 1){
            path = GlobalStatic.uploadPath + "/img/news";//
            modelpath = "/img/news/";
        }

        if(path == null){
            logger.error("没有可上传的路径");
            return null;
        }
        File fileP = new File(path);
        if(! fileP.exists())
        {
            fileP.mkdirs();
        }
        Map<String,String> paths = new HashMap<>();
        paths.put("path",path);
        paths.put("modelpath",modelpath);
        return paths;
    }

    /**
     * 多文件上传
     * @param file
     * @param type
     * @return
     */
    public static List<String> MultiUpload(MultipartFile[] file, int type){

        List<String> modelPath = Lists.newArrayList();
        for (int i = 0; i < file.length; i++) {

            modelPath.add(upload(file[i],type));
        }
        return modelPath;
    }

    public static String uploadBase64(String strBase64, int userType, String file_type)
    {
        String string = strBase64;
        Map<String ,String > paths = checkFilePath(userType);
        Long now = Long.parseLong(new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
        Long random = (long) (Math.random() * now);
        String fileName = paths.get("path") + "/" + now + "" + random + "." + file_type; //生成的新文件
        try {
            // 解码，然后将字节转换为文件
            byte[] bytes = new BASE64Decoder().decodeBuffer(string);   //将字符串转换为byte数组
            ByteArrayInputStream in = new ByteArrayInputStream(bytes);
            byte[] buffer = new byte[1024];
            FileOutputStream out = new FileOutputStream(fileName);
            /*总字节数*/
            int bytesum = 0;
            int byteread = 0;
            while ((byteread = in.read(buffer)) != -1) {
                bytesum += byteread;
                out.write(buffer, 0, byteread); //文件写操作
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        return paths.get("modelpath") + now + "" + random + "." + file_type;
    }

    /**
     * 上传方法2
     * @param file 文件
     * 七牛云端上传
     */
    public static Map sevenUpload(MultipartFile file) {
        DefaultPutRet putRet = null;
        int height = 0;
        int width = 0;
        try {
            // Getting image data from a InputStream
            InputStream is = file.getInputStream();
            // 调用put方法上传
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] b = new byte[1024];
            int len = -1;
            while ((len = is.read(b)) != -1) {
                bos.write(b, 0, len);
            }
            byte[] uploadBytes = bos.toByteArray();
            SimpleImageInfo imageInfo = new SimpleImageInfo(uploadBytes);
            Auth auth = Auth.create(GlobalStatic.qiNiuAK, GlobalStatic.qiNiuSK);
            String upToken = auth.uploadToken("mj-gw");
            Response res = SevenAuthUtil.uploadManager.put(uploadBytes, rename(file.getOriginalFilename()), upToken);
            putRet = new Gson().fromJson(res.bodyString(), DefaultPutRet.class);
            System.out.println(putRet.key);//key文件名
            System.out.println(putRet.hash);//hash七牛返回的文件存储的地址，可以使用这个地址加七牛给你提供的前缀访问到这个视频。
            width = imageInfo.width;
            height = imageInfo.height;
        }
        catch (IOException e1)
        {
        }
        Map param = Maps.newHashMap();
        param.put("path", putRet == null ? null : "https://static-www.mejour.cn/" + putRet.key);
        param.put("height", height);
        param.put("width", width);
        return param;
    }

    /**
     * 给图片增加图片水印
     *
     * @param inputImg
     *            -源图片，要添加水印的图片
     * @param markImg
     *            - 水印图片
     * @param outputImg
     *            -输出图片(可以是源图片)
     * @param width
     *            - 水印图片宽度
     * @param height
     *            -水印图片高度
     * @param x
     *            -横坐标，相对于源图片
     * @param y
     *            -纵坐标，同上
     */
    public void mark(String inputImg, String markImg, String outputImg, int width, int height, int x, int y) {
        // 读取原图片信息
        File inputImgFile = null;
        File markImgFile = null;
        Image img = null;
        Image mark = null;
        try {
            if (inputImg != null && markImg != null) {
                inputImgFile = new File(inputImg);
                markImgFile = new File(markImg);
            }
            if (inputImgFile != null && inputImgFile.exists() && inputImgFile.isFile() && inputImgFile.canRead()) {

                img = ImageIO.read(inputImgFile);

            }
            if (markImgFile != null && markImgFile.exists() && markImgFile.isFile() && markImgFile.canRead()) {

                mark = ImageIO.read(markImgFile);

            }
            int imgWidth = img.getWidth(null);
            int imgHeight = img.getHeight(null);
            BufferedImage bufImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
            mark(bufImg, img, mark, width, height, x, y);
            FileOutputStream outImgStream = new FileOutputStream(outputImg);
            ImageIO.write(bufImg, "jpg", outImgStream);
            outImgStream.flush();
            outImgStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 加文字水印
    public void mark(BufferedImage bufImg, Image img, String text, Font font, Color color, int x, int y) {
        Graphics2D g = bufImg.createGraphics();
        g.drawImage(img, 0, 0, bufImg.getWidth(), bufImg.getHeight(), null);
        g.setColor(color);
        g.setFont(font);
        g.drawString(text, x, y);
        g.dispose();
    }

    // 加图片水印
    public void mark(BufferedImage bufImg, Image img, Image markImg, int width, int height, int x, int y) {
        Graphics2D g = bufImg.createGraphics();
        g.drawImage(img, 0, 0, bufImg.getWidth(), bufImg.getHeight(), null);
        g.drawImage(markImg, bufImg.getWidth()-x, y, width, height, null);
        g.dispose();
    }

    /**
     * 给图片增加文字水印
     *
     * @param imgPath
     *            -要添加水印的图片路径
     * @param outImgPath
     *            -输出路径
     * @param text-文字
     * @param font
     *            -字体
     * @param color
     *            -颜色
     * @param x
     *            -文字位于当前图片的横坐标
     * @param y
     *            -文字位于当前图片的竖坐标
     */
    public void mark(String imgPath, String outImgPath, String text, Font font, Color color, int x, int y) {
        try {
            // 读取原图片信息
            File imgFile = null;
            Image img = null;
            if (imgPath != null) {
                imgFile = new File(imgPath);
            }
            if (imgFile != null && imgFile.exists() && imgFile.isFile() && imgFile.canRead()) {
                img = ImageIO.read(imgFile);
            }
            int imgWidth = img.getWidth(null);
            int imgHeight = img.getHeight(null);
            // 加水印
            BufferedImage bufImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
            mark(bufImg, img, text, font, color, x, y);
            // 输出图片
            FileOutputStream outImgStream = new FileOutputStream(outImgPath);
            ImageIO.write(bufImg, "jpg", outImgStream);
            outImgStream.flush();
            outImgStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static class SimpleImageInfo {
        private int height;
        private int width;
        private String mimeType;

        public SimpleImageInfo(File file) throws IOException {
            InputStream is = new FileInputStream(file);
            try {
                processStream(is);
            } finally {
                is.close();
            }
        }

        public SimpleImageInfo(InputStream is) throws IOException {
            processStream(is);
        }

        public SimpleImageInfo(byte[] bytes) throws IOException {
            InputStream is = new ByteArrayInputStream(bytes);
            try {
                processStream(is);
            } finally {
                is.close();
            }
        }

        private void processStream(InputStream is) throws IOException {
            int c1 = is.read();
            int c2 = is.read();
            int c3 = is.read();

            mimeType = null;
            width = height = -1;

            if (c1 == 'G' && c2 == 'I' && c3 == 'F') { // GIF
                is.skip(3);
                width = readInt(is,2,false);
                height = readInt(is,2,false);
                mimeType = "image/gif";
            } else if (c1 == 0xFF && c2 == 0xD8) { // JPG
                while (c3 == 255) {
                    int marker = is.read();
                    int len = readInt(is,2,true);
                    if (marker == 192 || marker == 193 || marker == 194) {
                        is.skip(1);
                        height = readInt(is,2,true);
                        width = readInt(is,2,true);
                        mimeType = "image/jpeg";
                        break;
                    }
                    is.skip(len - 2);
                    c3 = is.read();
                }
            } else if (c1 == 137 && c2 == 80 && c3 == 78) { // PNG
                is.skip(15);
                width = readInt(is,2,true);
                is.skip(2);
                height = readInt(is,2,true);
                mimeType = "image/png";
            } else if (c1 == 66 && c2 == 77) { // BMP
                is.skip(15);
                width = readInt(is,2,false);
                is.skip(2);
                height = readInt(is,2,false);
                mimeType = "image/bmp";
            } else {
                int c4 = is.read();
                if ((c1 == 'M' && c2 == 'M' && c3 == 0 && c4 == 42)
                        || (c1 == 'I' && c2 == 'I' && c3 == 42 && c4 == 0)) { //TIFF
                    boolean bigEndian = c1 == 'M';
                    int ifd = 0;
                    int entries;
                    ifd = readInt(is,4,bigEndian);
                    is.skip(ifd - 8);
                    entries = readInt(is,2,bigEndian);
                    for (int i = 1; i <= entries; i++) {
                        int tag = readInt(is,2,bigEndian);
                        int fieldType = readInt(is,2,bigEndian);
                        int valOffset;
                        if ((fieldType == 3 || fieldType == 8)) {
                            valOffset = readInt(is,2,bigEndian);
                            is.skip(2);
                        } else {
                            valOffset = readInt(is,4,bigEndian);
                        }
                        if (tag == 256) {
                            width = valOffset;
                        } else if (tag == 257) {
                            height = valOffset;
                        }
                        if (width != -1 && height != -1) {
                            mimeType = "image/tiff";
                            break;
                        }
                    }
                }
            }
            if (mimeType == null) {
                throw new IOException("Unsupported image type");
            }
        }

        private int readInt(InputStream is, int noOfBytes, boolean bigEndian) throws IOException {
            int ret = 0;
            int sv = bigEndian ? ((noOfBytes - 1) * 8) : 0;
            int cnt = bigEndian ? -8 : 8;
            for(int i=0;i<noOfBytes;i++) {
                ret |= is.read() << sv;
                sv += cnt;
            }
            return ret;
        }

        public int getHeight() {
            return height;
        }

        public void setHeight(int height) {
            this.height = height;
        }

        public int getWidth() {
            return width;
        }

        public void setWidth(int width) {
            this.width = width;
        }

        public String getMimeType() {
            return mimeType;
        }

        public void setMimeType(String mimeType) {
            this.mimeType = mimeType;
        }

        @Override
        public String toString() {
            return "MIME Type : " + mimeType + "\t Width : " + width
                    + "\t Height : " + height;
        }
    }
}
